package com.mvc.framework.web;

import java.lang.reflect.ParameterizedType;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.extremecomponents.table.core.TableConstants;
import org.extremecomponents.table.limit.Limit;
import org.springframework.web.bind.annotation.RequestMapping;

import com.mvc.framework.dao.HibernateWebUtils;
import com.mvc.framework.dao.PropertyFilter;
import com.mvc.framework.model.Auditable;
import com.mvc.framework.model.BaseEntity;
import com.mvc.framework.model.CommonAuditableEntity;
import com.mvc.framework.util.PageSearch;
import com.mvc.framework.util.PageUtils;

/**
 * Base controller for page query class The entrance is page method The sub
 * class can override preparePage、handelPage
 * 
 * @author pubx 2010-3-29 02:27:45
 */
public abstract class PageController<T> extends BaseController<T> {

	private static final String	  EQB_REC_STATUS	= "EQB_recStatus";

	protected static final String	LIST_ITEMS	 = "items";

	protected static final String	TOTAL_ROWS	 = "totalRows";

	private static final String	  SEARCH_PREFIX	 = "search_";

	private static final String	  PAGE_SUFFIX	 = "_page";

	private static final Logger	  LOGGER	     = Logger.getLogger(PageController.class);

	public static final int	      IS_NOT_BACK	 = 0;

	public static final int	      IS_BACK	     = 1;

	/**
	 * Go into the list page
	 * 
	 * @param request
	 * @param t
	 * @param backPage
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/page")
	public String page(HttpServletRequest request, T t, Integer backPage) throws Exception {
		Limit limit = PageUtils.getLimit(request);
		PageSearch page = preparePage(request, limit);
		String result = handlePage(request, page);
		afterPage(request, page, backPage);
		return result;
	}

	protected void afterPage(HttpServletRequest request, PageSearch page, Integer backPage) {
		request.setAttribute(LIST_ITEMS, page.getList());
		request.setAttribute(TOTAL_ROWS, page.getTotalCount());
		// save query parameters
		if (backPage == null || IS_BACK != backPage || !PageUtils.isExported(request)) {
			StringBuilder query = new StringBuilder(50);
			Iterator it = request.getParameterMap().entrySet().iterator();
			while (it.hasNext()) {
				Map.Entry entry = (Map.Entry) it.next();
				query.append(entry.getKey()).append("=").append(MessageUtils.urlEncodeWithUtf8(((String[])entry.getValue())[0].toString())).append("&");
			}
			request.getSession().setAttribute(request.getRequestURI() + PAGE_SUFFIX, query.toString());
		}
	}

	/**
	 * Query history data
	 * 
	 * @param request
	 * @param t
	 * @param backPage
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/pageHistory")
	public String pageHistory(HttpServletRequest request, T t, Integer backPage) throws Exception {
		Limit limit = PageUtils.getLimit(request);
		PageSearch page = preparePageHistory(request, limit);
		String result = handlePageHistory(request, page);
		request.setAttribute(LIST_ITEMS, page.getList());
		limit.setRowAttributes(page.getTotalCount(), PageSearch.DEFAULT_PAGE_SIZE);
		request.setAttribute(TOTAL_ROWS, page.getTotalCount());
		return result;
	}

	protected PageSearch preparePage(HttpServletRequest request, Limit limit) {
		PageSearch page = PageUtils.getPageSearch(request, limit);
		List<PropertyFilter> propertyFilters = HibernateWebUtils.buildPropertyFilters(request, SEARCH_PREFIX);
		Class entityClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		page.setEntityClass(entityClass);
		try {
			if (CommonAuditableEntity.class.isAssignableFrom(entityClass)) {
				PropertyFilter propertyFilter = new PropertyFilter(EQB_REC_STATUS, String.valueOf(Auditable.REC_STATUS_VALID));
				propertyFilters.add(propertyFilter);
				if (null == page.getSortProperty()) {
					page.setSortProperty("id");
					page.setSortOrder("desc");
				}
			} else if (BaseEntity.class.isAssignableFrom(entityClass)) {
				if (null == page.getSortProperty()) {
					page.setSortProperty("id");
					page.setSortOrder("desc");
				}
			}
		} catch (Exception e) {
			LOGGER.error("preparePage", e);
		}
		page.setFilters(propertyFilters);
		return page;
	}

	protected PageSearch preparePageHistory(HttpServletRequest request, Limit limit) {
		PageSearch page = PageUtils.getPageSearch(request, limit);
		List<PropertyFilter> propertyFilters = HibernateWebUtils.buildPropertyFilters(request, SEARCH_PREFIX);
		Class entityClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		page.setEntityClass(entityClass);
		try {
			if (CommonAuditableEntity.class.isAssignableFrom(entityClass)) {
				PropertyFilter propertyFilter = new PropertyFilter(EQB_REC_STATUS, String.valueOf(Auditable.REC_STATUS_INVALID));
				propertyFilters.add(propertyFilter);
			}
			if (null == page.getSortProperty()) {
				page.setSortProperty("createdOn");
				page.setSortOrder("desc");
			}
		} catch (Exception e) {
			LOGGER.error("preparePageHistory", e);
		}
		page.setFilters(propertyFilters);
		return page;
	}

	/**
	 * Go back to list page
	 * 
	 * @param request
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/back")
	public String back(HttpServletRequest request) throws Exception {
		String requestUrl = request.getRequestURI();
		requestUrl = requestUrl.replace("/back", "/page");
		// Get page search from session
		String parameters = (String) request.getSession().getAttribute(requestUrl + PAGE_SUFFIX);
		if (parameters != null) {
			return "redirect:page?" + parameters;
		}
		return page(request, null, IS_BACK);
	}

	protected String handlePage(HttpServletRequest request, PageSearch page) {
		getEntityManager().find(page);
		return getFileBasePath() + "list" + getActualArgumentType().getSimpleName();
	}

	protected String handlePageHistory(HttpServletRequest request, PageSearch page) {
		getEntityManager().find(page);
		return getFileBasePath() + "list" + getActualArgumentType().getSimpleName() + "History";
	}
}
